# Using Materials

One of the feature of nkAstraeus is called Materials. Materials are abstractions of nkGraphic's Shader and Program combo. They do so behind an API from where it is possible to drive their behavior. When using them, you don't need to worry about HLSL or constant buffers. Just set them up, and use them for shade entities.

In this tutorial, we will see the general logic to use them. For illustration purpose, we will use the physically based shading material, aka PbsMaterial. Let's dig in !

## Managing materials

Within the component, any Material is considered a resource. If you did tutorials from other components, you will see it coming : we will query them through their dedicated MaterialManager. Let's include what we need first :

#include <NilkinsAstraeus/Graphics/Materials/Utils/PbsEnvironmentMapFilter.h> #include <NilkinsAstraeus/Graphics/Materials/Pbs/PbsMaterial.h> #include <NilkinsAstraeus/Graphics/Materials/MaterialManager.h>

As we will work with the PbsMaterial, we include its header. Let's see how we can retrieve the material :

// Allocate the material nkAstraeus::PbsMaterial* mat = (nkAstraeus::PbsMaterial*)nkAstraeus::MaterialManager::getInstance()->createOrRetrieve("mat", nkAstraeus::MATERIAL_TYPE::PBS) ;

Through the MaterialManager, we request the material retrieval. The createOrRetrieve function will retrieve the material if the name is attached to one. However, if it doesn't exist, it will be created before retrieval. Next argument is the type of material we want to create, if non existing.

The manager returns an instance of Material. This is the base class for the materials available, but as such, we need to cast it ourselves to use its API. In doubt, you can check the API documentation about createOrRetrieve, but for one given type from the enumeration, a material class will correspond. Here, we request a MATERIAL_TYPE::PBS, which corresponds to a PbsMaterial.

Now that we have our material, what we need is to set it up.

mat->setMetalness(0.7f) ; mat->setRoughnessGlossiness(0.5f) ; mat->setEnvironmentColor(nkMaths::Vector(0.2f, 0.2f, 0.2f)) ; // And don't forget to load it so that it compiles the program and prepare the shader mat->load() ;

First step is to set up the parameters we want. Then, we need to call the method load. The method call will initialize all the internal memory required. If it succeeds, the shader will be ready to use.

Once the material is ready, the way to use it is to assign it to an Entity within nkGraphics :

// Retrieve the queue we will use nkGraphics::RenderQueue* rq = nkGraphics::RenderQueueManager::getInstance()->get(nkGraphics::RenderQueueManager::DEFAULT_RENDER_QUEUE) ; // Declare the entity, to feed the rendering information nkGraphics::Entity* ent = rq->addEntity() ; // The material is loaded, we can retrieve its shader to fit in within the entity ent->setRenderInfo(nkGraphics::EntityRenderInfo(mesh, mat->getShader())) ;

For context, the whole code for entity creation has been added too. The thing to do is to assign the shader within the entity, and we're good to go ! Now, the entity will use the shader provided by the material, which is exactly what is needed to use the material.

To demonstrate a bit what the material does, here is a screenshot of a row of spheres, all rendered with their own material.
Each of them has a different roughness value, ranging from 0 to 1 by increments of 0.1. The materials were set to be lit by an environment map and an irradiance map generated on the fly (see tips). Environment maps like these can be found on this excellent website.
We won't go over more details here as this kind of process is already detailed within the nkGraphics tutorial course. However, the code used to reach this result is given with the tutorial.

Roughness, descending from left to right

Notice how the reflections get blurrier and blurrier, as typical with real material's reflections.

## Updating a material

So now we have a material, with some parameters set. Loading a material will partially lock the parameters in place. This means that while it is possible to change them on the fly without reloading the material, changing parameters that are not of the same "family" will require a reloading.

For instance, let's imagine that we fed the environment through a texture. It means that we can change that texture without needing to reload the material. However, if we wish to set and use the environment color, this would mean that we need to reload the material for it to work with the environment color.

It is true for all individual parameters that can be set through different kind of data. It is possible to update a parameter, but not to change its nature.

## Tips

### Generating an irradiance map

Irradiance maps are a main aspect, with an environment map, to generate believable results. Often, if there is a mismatch between both, result will seem off.

Environment maps can be found easily on the right websites. However, irradiance maps often need to be generated by hand. The nkEngine luckily offers tools to help with that.

Within the nkAstraeus component, we will use the PbsEnvMapFilter class that can generate irradiance using spherical harmonics. Let's see it in action :

// Prepare the environment map nkGraphics::Texture* envMap = nkGraphics::TextureManager::getInstance()->createOrRetrieve("ENV") ; envMap->setPath("Data/environment.hdr") ; envMap->load() ; // Compute dynamically the irradiance map nkGraphics::Texture* irrMap = nkGraphics::TextureManager::getInstance()->createOrRetrieve("IRR") ; nkAstraeus::System::getInstance()->getPbsEnvironmentMapFilter()->requestIrradianceComputing(envMap, irrMap) ;

Simply request the generation from a texture already existing, and request a load. This will result, for instance, in :

Top, the source environment map, bottom, the computed irradiance map

### Boosting performances

The PbsEnvMapFilter also has tools to pre-process environment maps, and boost the performances when rendering the PbsMaterial in particular. Be sure to check its requestEnvMapFiltering method when using IBL.

## Conclusion

Through this tutorial, we saw that materials offer a higher level control over dedicated shaders. As a result, they are easily usable within nkGraphics.

Within nkAstraeus, they are considered as resources, meaning that there is a dedicated manager we have to dialog with, and that we need to load them after setup. After loading, there is still some flexibility to change the parameters, up to some extent before the material needs to be reloaded.

And with this, this tutorial is done. Other features will be demonstrated when time comes !